package com.shop.loan.service.impl;

import com.alibaba.fastjson.JSON;
import com.shop.loan.mapper.*;
import com.shop.loan.model.common.Code;
import com.shop.loan.model.common.ResResult;
import com.shop.loan.model.entity.*;
import com.shop.loan.model.enums.*;
import com.shop.loan.model.vo.*;
import com.shop.loan.redis.RedisCache;
import com.shop.loan.redis.RedisLockUtil;
import com.shop.loan.redis.RedisUtil;
import com.shop.loan.rentaldata.RentalPayUtil;
import com.shop.loan.service.AsyncService;
import com.shop.loan.service.PayService;
import com.shop.loan.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Jedis;
import xyz.erupt.core.util.MD5Util;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.UUID;

@Slf4j
@Service
public class PayServiceImpl implements PayService {

    @Value("${api.rental_pay.apiKey}")
    private String apiKey;

    @Resource
    RedisUtil redisUtil;

    @Resource
    SysMsgUtil sysMsgUtil;

    @Resource
    AsyncService asyncService;

    @Resource
    LoanOrderBillByMybatisMapper loanOrderBillByMybatisMapper;

    @Resource
    LoanOrderPayLogByMybatisMapper loanOrderPayLogByMybatisMapper;

    @Resource
    LoanOrderByMybatisMapper loanOrderByMybatisMapper;

    @Resource
    UserByMybatisMapper userByMybatisMapper;

    @Resource
    PayOrderThirdByMybatisMapper payOrderThirdByMybatisMapper;

    @Resource
    LoanOrderUtil loanOrderUtil;

    @Resource
    RentalPayUtil rentalPayUtil;

    @Resource
    Util util;

    @Resource
    RedisLockUtil redisLockUtil;

    /**
     * 准备支付
     *
     * @param payVo
     * @param isWithhold 是否代扣  true：是
     * @return
     */
    @Override
    public ResResult readyPay(PayVo payVo, boolean isWithhold) {
        Jedis jedis = redisUtil.getJedis();
        String lockKey = RedisCache.payLock + payVo.getOrderId();
        String lockValue = UUID.randomUUID().toString();
        try {
            if (!redisLockUtil.lock(jedis, lockKey, lockValue)) {
                log.error("【payLock】正在支付中");
                return new ResResult(Code.PAY_ING);
            }

            LoanOrderByMybatis loanOrderByMybatis = loanOrderByMybatisMapper.selectByPrimaryKey(payVo.getOrderId());
            if (loanOrderByMybatis.getStatus() != OrderStatus.underway.getStatus().intValue()) {
                return new ResResult(Code.ORDER_STATUS_NOT_PAY);
            }

            //查询是否有进行中的付款
            Integer payIngNum = payOrderThirdByMybatisMapper.selectPayTypeIngByOrder(payVo.getOrderId(), payVo.getPayType());
            if (payIngNum != null && payIngNum > 0) {
                return new ResResult(Code.PAY_ING);
            }

            BigDecimal amount;
            LoanOrderBillByMybatis loanOrderBillByMybatis = loanOrderBillByMybatisMapper.selectFirstUnPay(payVo.getOrderId());
            if (loanOrderBillByMybatis == null || loanOrderBillByMybatis.getId() == null) {
                return new ResResult(Code.NOT_NEED_PAY);
            }
            BigDecimal payTypeSum = loanOrderPayLogByMybatisMapper.selectSumByBillId(loanOrderBillByMybatis.getId(), null, payVo.getPayType());
            payTypeSum = payTypeSum == null ? BigDecimal.ZERO : payTypeSum;
            loanOrderBillByMybatis.setPayMoney(payTypeSum);
            if (payVo.getPayType() == PayType.principal_interest.getType().intValue()) {
                amount = Util.getUnPayMoneyByPi(loanOrderBillByMybatis);
            } else {
                amount = Util.getUnPayMoneyByGoods(loanOrderByMybatis.getShopMoney(), loanOrderByMybatis.getShopMoney());
            }
            Integer period = loanOrderBillByMybatis.getPeriod();

            if (amount.compareTo(BigDecimal.ZERO) <= 0) {
                return new ResResult(Code.NOT_NEED_PAY);
            }

            if (payVo.getAmount() != null && payVo.getAmount().compareTo(BigDecimal.ZERO) > 0) {
                //自定义还款金额  若自定义金额<账单金额  则还自定义金额 否则归还账单金额
                if (payVo.getAmount().compareTo(amount) < 0) {
                    amount = payVo.getAmount();
                }
            }

            String outTradeNo = Util.getOutTradeNo();
            UserByMybatis userByMybatis = userByMybatisMapper.selectByPrimaryKey(loanOrderByMybatis.getUserId());
            /**
             * 请求支付 生成支付订单
             */
            PayOrderThirdByMybatis payOrderThirdByMybatis = new PayOrderThirdByMybatis();
            RentalPayVo rentalPayVo = new RentalPayVo();
            rentalPayVo.setOrderNo(outTradeNo);
            rentalPayVo.setAmount(amount);
            rentalPayVo.setRealName(userByMybatis.getCardName());
            rentalPayVo.setIdNo(userByMybatis.getCardNum());
            rentalPayVo.setMobile(userByMybatis.getMobile());
            rentalPayVo.setBindCardId(payVo.getBindCardId());
            rentalPayVo.setUserIpAddr(payVo.getOpIp() == null ? "182.104.40.84" : payVo.getOpIp());
            rentalPayVo.setOrderId(loanOrderByMybatis.getId() + "");
            rentalPayVo.setUserId(util.getUserId(userByMybatis.getId()));
            rentalPayVo.setPayType(payVo.getPayType());
            ResResult payRes = rentalPayUtil.pay(rentalPayVo);
            if (payRes.getCode() == Code.SUCCESS.getCode().intValue()) {
                payOrderThirdByMybatis.setStatus(PayStatus.wait.getStatus());
                payOrderThirdByMybatis.setSerialNo(payRes.getData().toString());
            } else {
                payOrderThirdByMybatis.setReason(payRes.getMsg());
                payOrderThirdByMybatis.setStatus(PayStatus.fail.getStatus());
            }
            payOrderThirdByMybatis.setPeriod(period);
            payOrderThirdByMybatis.setUserId(payVo.getOpId());
            payOrderThirdByMybatis.setOrderId(payVo.getOrderId());
            payOrderThirdByMybatis.setOutTradeNo(outTradeNo);
            payOrderThirdByMybatis.setAmount(amount);
            payOrderThirdByMybatis.setCreateTime(new Date());
            payOrderThirdByMybatis.setPayForm(PayFormType.sumpay.getType());
            payOrderThirdByMybatis.setPayClient(payVo.getPFrom());
            payOrderThirdByMybatis.setPayType(payVo.getPayType());
            payOrderThirdByMybatis.setType(PayOrderType.pay.getType());
            payOrderThirdByMybatis.setRemark(payVo.getRemark());
            payOrderThirdByMybatisMapper.insertSelective(payOrderThirdByMybatis);
            return payRes;
        } catch (Exception e) {
            e.printStackTrace();
            log.error(Util.GetErrorDetails(e));
        } finally {
            if (jedis != null) {
                redisLockUtil.release(jedis, lockKey, lockValue);
                jedis.close();
            }
        }
        return new ResResult(Code.PAY_FAIL);
    }

    @Override
    public ResResult payNotify(RentalPayBackVo rentalPayBackVo) {
        if (!StringUtils.hasLength(rentalPayBackVo.getSerial_no()) || rentalPayBackVo.getStatus() == null
                || !StringUtils.hasLength(rentalPayBackVo.getSign())) {
            return new ResResult(Code.PARAM_LACK);
        }
        PayOrderThirdByMybatis payOrderThirdByMybatis = payOrderThirdByMybatisMapper.selectBySerialNo(rentalPayBackVo.getSerial_no());
        if (payOrderThirdByMybatis == null || payOrderThirdByMybatis.getStatus() != PayStatus.wait.getStatus().intValue()) {
            return new ResResult(Code.PARAM_INVALID);
        }

        if (!MD5Util.digest(rentalPayBackVo.getSerial_no() + "_" + apiKey).trim().equals(rentalPayBackVo.getSign())) {
            return new ResResult(Code.SIGN_ERROR);
        }
        ResResult resResult = new ResResult(Code.SUCCESS);
        PayOrderThirdByMybatis updateLog = new PayOrderThirdByMybatis();
        updateLog.setId(payOrderThirdByMybatis.getId());
        if (rentalPayBackVo.getStatus() == LoanStatus.fail.getType().intValue()) {
            updateLog.setStatus(LoanStatus.fail.getType());
            updateLog.setReason(rentalPayBackVo.getMsg());
        } else if (rentalPayBackVo.getStatus() == LoanStatus.success.getType().intValue()) {
            updateLog.setSuccessTime(new Date());
            updateLog.setStatus(LoanStatus.success.getType());
            if (payOrderThirdByMybatis.getType() == PayOrderType.loan.getType().intValue()) {
                //放款成功
                redisUtil.hset(RedisCache.orderLoanSuccessMap, payOrderThirdByMybatis.getOrderId() + "", "1");
                LoanOrderByMybatis updateOrder = new LoanOrderByMybatis();
                updateOrder.setStatus(OrderStatus.underway.getStatus());
                updateOrder.setLoanTime(new Date());
                updateOrder.setId(payOrderThirdByMybatis.getOrderId());
                loanOrderByMybatisMapper.updateByPrimaryKeySelective(updateOrder);

                UserByMybatis user = userByMybatisMapper.selectByOrderId(payOrderThirdByMybatis.getOrderId());
                if (user != null && user.getMobile() != null) {
                    //放款成功通知
                    sysMsgUtil.sendLoanSuccess(user.getMobile());
                }
                //校验是否需要推送给渠道
                asyncService.notifyCheck(payOrderThirdByMybatis.getOrderId());
                //生成合同
                redisUtil.lpush(RedisCache.waitCreateContract, payOrderThirdByMybatis.getOrderId() + "");
            } else {
                //还款
                PayOrderByOfflineVo payOrderByOfflineVo = new PayOrderByOfflineVo();
                payOrderByOfflineVo.setOnline(true);
                payOrderByOfflineVo.setPeriod(payOrderThirdByMybatis.getPeriod());
                payOrderByOfflineVo.setOrderPayId(payOrderThirdByMybatis.getSerialNo());
                payOrderByOfflineVo.setOrderId(payOrderThirdByMybatis.getOrderId());
                payOrderByOfflineVo.setPaymentType(PaymentType.tongtong.getType());
                payOrderByOfflineVo.setPayType(payOrderThirdByMybatis.getPayType());
                payOrderByOfflineVo.setMoney(payOrderThirdByMybatis.getAmount());
                ResResult payRes = loanOrderUtil.orderPay(payOrderByOfflineVo);
                log.info("1、还款操作结束参数:{}，结果：{}", JSON.toJSONString(payOrderByOfflineVo), JSON.toJSONString(payRes));
                if (payRes.getCode() != Code.SUCCESS.getCode().intValue()) {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    payRes = loanOrderUtil.orderPay(payOrderByOfflineVo);
                    log.info("2、还款操作结束参数:{}，结果：{}", JSON.toJSONString(payOrderByOfflineVo), JSON.toJSONString(payRes));
                    if (payRes.getCode() != Code.SUCCESS.getCode().intValue()) {
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        payRes = loanOrderUtil.orderPay(payOrderByOfflineVo);
                        log.info("3、还款操作结束参数:{}，结果：{}", JSON.toJSONString(payOrderByOfflineVo), JSON.toJSONString(payRes));
                    }
                }
                resResult = payRes;
            }
        }
        if (payOrderThirdByMybatis.getType() == PayOrderType.loan.getType().intValue()) {
            redisUtil.hdel(RedisCache.orderLoanIngMap, payOrderThirdByMybatis.getOrderId() + "");
        }
        payOrderThirdByMybatisMapper.updateByPrimaryKeySelective(updateLog);
        return resResult;
    }


}
